package com.charging.business.media;

import com.alibaba.fastjson2.annotation.JSONField;
import com.charging.business.enums.Issuer;
import com.charging.business.enums.PassStatus;
import com.charging.business.enums.Vtype;
import com.charging.business.utils.DateEx;
import lombok.Data;

import java.util.Date;

/**
 * 双片式OBU缴费信息文件(DF01/EF04)解码信息
 * @author lzj
 */
@Data
public class ObuEf04Model {
    /**
     * 分省信息最大数量(20个)
     */
    public static final int MAX_PROV_COUNT = 20;

    /**
     * 用户卡0019文件前39BYTES(到nVSign)(315-353,39,bn)
     */
    @JSONField(ordinal = 1)
    public Card001939Model uc0019 = new Card001939Model();

    /**
     * 用户卡0015文件前20BYTES(到cardNo)(354-373,20,bn)
     */
    @JSONField(ordinal = 2)
    public Card001520Model uc0015 = new Card001520Model();

    /**
     * 用户类型写入0015文件第 41 字节(374-374,1,n)
     */
    @JSONField(ordinal = 3)
    public int vehicleUserType = 0;

    /**
     * 累计通行省份数量(375-375,1,n)
     * 根据 OBU返回状态判断后累加写入。入口置 1 出口清 0
     */
    @JSONField(ordinal = 4)
    public int provCount = 0;

    /**
     * 全程累计应收金额(376-378,3,n)
     * 单位：分
     */
    @JSONField(ordinal = 5)
    public int sumPayFee = 0;

    /**
     * 全程累计实收金额(379-381,3,n)
     * 单位：分
     */
    @JSONField(ordinal = 6)
    public int sumFee = 0;

    /**
     * 全程累计成功次数(382-383,2,n)
     * ETC门架系统（含兼具门架功能的收费站入出口）根据 OBU返回状态判断后累加写入
     */
    @JSONField(ordinal = 7)
    public int sumOkCount = 0;

    /**
     * 全程累计计费里程(384-386,3,n
     * 单位米
     */
    @JSONField(ordinal = 8)
    public int sumMileage = 0;

    /**
     * 全程累计无卡次数(387-387,1,n)
     */
    @JSONField(ordinal = 9)
    public int sumNoCardCount = 0;

    /**
     * 本省入口HEX编码(388-390,3,bn)
     * 入口收费站（本省为入口匝道HEX,外省可能写入 3 字节 0x00）或省界入口门架 HEX 码
     */
    @JSONField(ordinal = 10)
    public String provEntryHex = "000000";

    /**
     * 本省累计应收金额(391-393,3,n)
     * 单位：分
     * ETC 门架系统（含兼具门架功能的收费站入出口）根据 OBU 返回状态判断后累加写入应收金额，进入下一省后重新计数
     */
    @JSONField(ordinal = 11)
    public int provSumPayFee = 0;

    /**
     * 本省累计成功次数(394-394,1,n)
     * ETC 门架系统（含兼具门架功能的收费站入出口）根据 OBU 返回状态判断后累加写入，进入下一省后重新计数
     */
    @JSONField(ordinal = 12)
    public int provSumCount = 0;

    /**
     * 本省累计实收金额(395-397,3,n)
     * ETC 门架系统（含兼具门架功能的收费站入出口）根据 OBU 返回状态判断后累加写入，进入下一省后重新计数
     */
    @JSONField(ordinal = 13)
    public int provSumFee = 0;

    /**
     * 加密摘要(398-405,8,bn)
     * 入出口默认为0x0000000000000000
     */
    @JSONField(ordinal = 14)
    public String mark = "0000000000000000";

    /**
     * 通行省份累计实收金额(406-485,80,bn)
     * 顺序记录，每过一个省增加4个字节，格式为：AABBBBBB-AA为省份的BCD区号;BBBBBB-为该省累计实收金额(如：河南1分:0x41000001)
     * 最多记录20个分省信息
     */
    @JSONField(ordinal = 15)
    public ObuProvModel[] provTolls = new ObuProvModel[MAX_PROV_COUNT];

    /**
     * 构造函数
     */
    public ObuEf04Model() {
        for (int aa = 0; aa < MAX_PROV_COUNT; aa++) {
            provTolls[aa] = new ObuProvModel();
        }
    }

    /**
     * 获取绑定用户卡发行数据
     */
    public String ucIssuerId() {
        return uc0015.issueSign;
    }

    /**
     * 获取绑定用户卡网络编号
     */
    public String getCardWork() {
        return uc0015.cardWork;
    }

    /**
     * 获取8位入口HEX码
     */
    public String enStationHex8() {
        return uc0019.netWork + uc0019.enStationId;
    }

    /**
     * 获取入口特殊车辆标识
     */
    public int enVSign() {
        return uc0019.vehicleSign;
    }

    /**
     * 获取入口轴数
     */
    public int enAxis() {
        return uc0019.axleCount;
    }

    /**
     * 获取入口车型
     */
    public int enVType() {
        return uc0019.vehicleType;
    }

    /**
     * 获取入口计费车型
     *
     * @param obuVCls - OBU车种
     * @return - 计费车型
     * 客车等于入口车型
     * J1、MTC大件、甩挂车、J2及ETC大件会按轴数升降档、但不小于入口车型
     * 其他货车等于入口车型
     */
    public int enFeeVType(int obuVCls) {
        return Vtype.feeVType(obuVCls, enVSign(), enVType(), enAxis());
    }

    /**
     * 获取入口加收轴数
     * 车型为16、26的甩挂车及大件车，轴数大于6轴需要按轴数加收
     *
     * @param obuVCls - obu车种
     * @return - 加收轴数
     * =0 - 加收轴数为0
     * >0 - 需要加收的轴数
     */
    public int enFeeAddAxis(int obuVCls) {
        return Vtype.feeAddAxis(obuVCls, enVSign(), enVType(), enAxis());
    }

    /**
     * 获取入口车货总重
     */
    public int enWeight() {
        return uc0019.totalWeight;
    }

    /**
     * 获取入口车牌
     */
    public String enVPlate() {
        return String.format("%s_%d", uc0019.plateNumber, uc0019.plateColor);
    }

    /**
     * 获取入口时间
     */
    public long enTime() {
        return uc0019.enTime;
    }

    /**
     * 获取入口时间
     */
    public String enTime(String pattern) {
        return DateEx.ut2str((int) uc0019.enTime, pattern);
    }

    /**
     * 获取前序门架HEX
     */
    public String lastGantryHex() {
        return uc0019.preGantryNo;
    }

    /**
     * 获取过前序门架时间
     */
    public long lastGantryTime() {
        return uc0019.preGantryTime;
    }

    /**
     * 获取过前序门架时间
     */
    public String lastGantryTime(String pattern) {
        return DateEx.ut2str((int) uc0019.preGantryTime, pattern);
    }

    /**
     * 检查是否正常上道
     */
    public String tstEnStatus() {
        if (uc0019.applySign != 0xAA && uc0019.applySign != 0xBB) {
            return "上道异常";
        } else if (uc0019.applyLockSign != 0x00) {
            return "已锁定";
        } else if (uc0019.cardState != PassStatus.ETC_EN && uc0019.cardState != PassStatus.MIX_EN) {
            return "未上道";
        }
        return "";
    }

    /**
     * 检查是否本省入口
     */
    public boolean tstLocalEntry() {
        return uc0019.netWork.equals(Issuer.Issue140101.getProvinceCode());
    }

    /**
     * 检查当前行程是否为本省行程
     */
    public boolean tstLastLocal() {
        if (provEntryHex.isEmpty()) {
            return false;
        }
        if (provEntryHex.equals("000000")) {
            return false;
        }

        String netid = provEntryHex.substring(0, 2);
        return netid.equals("40") || netid.equals("61") || netid.equals("42") || netid.equals("43");
    }

    /**
     * 获取UT格式的入省时间
     * 因为EF04文件中未记录本省入省时间,因此：
     * 1)	若provEntyHex与本省入口匝道HEX相同，则用入口时间作为本省入省时间
     * 2)	若provEntyHex与前序门架HEX相同，则本省入省时间为用过前序门架时间
     * 3)	若不满足上述条件，则本省入省时间为过前序门架时间-30分钟
     */
    public long provEntryTime() {
        String entryHex = "40" + enStationHex8().replace(Issuer.Issue140101.getProvinceCode(), "");
        // 本省入口为本省收费站入口
        if (entryHex.equals(provEntryHex)) {
            // 本省入省时间为本省入口时间
            return this.enTime();
        } else {
            // 本省入口不为本省收费站入口
            // 本省入省时间为前序过门架时间
            String lastGHEX = this.lastGantryHex();
            // 前序门架为省入口门架
            if (lastGHEX.equals(provEntryHex)) {
                return this.lastGantryTime();
            }
        }
        return this.lastGantryTime() - 60 * 5;
    }

    /**
     * 获取字符串格式的入省时间
     * 因为EF04文件中未记录本省入省时间,因此：
     * 1)	若provEntyHex与本省入口匝道HEX相同，则用入口时间作为本省入省时间
     * 2)	若provEntyHex与前序门架HEX相同，则本省入省时间为用过前序门架时间
     * 3)	若不满足上述条件，则本省入省时间为过前序门架时间-30分钟
     *
     * @param pattern - 日期时间格式
     * @return
     */
    public String provEntryTime(String pattern) {
        return DateEx.ut2str((int) provEntryTime(), pattern);
    }

    /**
     * 分省信息测试
     */
    public boolean tstProvInfo() {
        int sum = 0;
        for (int aa = 0; aa < provCount && aa < provTolls.length; aa++) {
            sum += provTolls[aa].provinceToll;
        }

        //{{TODO:2024070801修改
        return sum == sumFee;
        //if (sumFee==0) {
        //	if (Math.abs(sumFee-sum)>1000)
        //		return false; 	//相差超过10元
        //}else {
        //	float rate = (float)sum/(float)sumFee;
        //	if (Float.compare(rate, 0.8f)<0)
        //		return false;	//小于80%
        //	else
        //	if (Float.compare(rate, 1.2f)>0)
        //		return false;	//大于120%
        //}}
    }

    /**
     * 获取入口至当前时间(秒)
     */
    public long runTimes() {
        return DateEx.dt2ut(new Date()) - uc0019.enTime;
    }

    public void mkProv(String strHex) {
        for (int aa = 0; aa < provTolls.length; aa++) {
            provTolls[aa].provinceId = "00";
            provTolls[aa].provinceToll = 0;
            strHex = strHex + "00000000";
        }
        if (strHex.length() % 8 != 0) {
            return;
        }
        for (int aa = 0; aa < provCount; aa++) {
            provTolls[aa].provinceId = strHex.substring(0, 2);
            provTolls[aa].provinceToll = Integer.parseInt(strHex.substring(2, 8), 16);
            strHex = strHex.substring(8);
        }
    }

//    public String provInfoHex() {
//        String ret = "";
//        for (int aa = 0; aa < provCount; aa++) {
//            DOBUPROVDD dd = provTolls[aa];
//            ret += DOBUPROVED.encoded(dd).toHexStr();
//        }
//        return ret;
//    }
}
